<?php
/**
 * | 节程 [ 节程赋能开发者，助力企业发展 ]
 * +----------------------------------------------------------------------
 *  | Copyright (c) 2020~2029 温州惊蛰网络科技有限公司 All rights reserved.
 * +----------------------------------------------------------------------
 *  | Licensed 节程并不是自由软件，未经许可不能去掉节程相关版权
 * +----------------------------------------------------------------------
 */


namespace app\index\util;


use app\index\model\Configuration;
use app\index\model\IntegralRecord;
use app\index\model\LotteryConfig;
use app\index\model\LotteryLog;
use app\index\model\LotteryLogistics;
use app\index\model\LotteryPrize;
use app\index\model\RechargeRecord;
use app\index\model\UserCash;
use app\index\model\UserCoupon;
use app\index\model\UserLottery;
use think\Exception;
use think\facade\Cache;
use think\facade\Db;

class Lottery
{
    protected static $user;
    protected $log;
    protected $price;
    protected $return;
    protected $record;
    protected $user_id;
    protected $lottery;

    public static function getUserLotteryFind(int $id, string $update_time, int $style) : Lottery
    {
        global $mid;
        $lottery = new Lottery;
        $lottery->user_id = $id;
        $lottery->lottery =
            UserLottery::where('user_id', $id)
                ->where('update_time','between', [date('Y-m-d H:i:s',strtotime($update_time) - 1),date('Y-m-d H:i:s',strtotime($update_time) + 1)])
                ->where('lottery_config_id', '=', function ($query) use ($style,$mid) {
                    $query->field('id')->name('lottery_config')
                    ->where('mall_id',$mid)
                    ->where('status', 1)
                    ->where('style', $style)
                    ->where('delete_time', null)
                    ->limit(0,1);
                })
                ->with(['Config'])
                ->append(['total_number'])
                ->lock(true)
                ->find();
        if (empty($lottery->lottery))
            throw new Exception('抽奖信息不存在',HTTP_SUCCESS);
        return $lottery;
    }


    public function  minusNumber() : Lottery{
        $this->lottery->save(['number' => $this->lottery->number - 1,'get_number' => $this->lottery->get_number + 1]);
        return $this;
    }

    public function lotteryJudge() : Lottery{
        $lottery = $this->lottery;
//        if ($lottery->total_number == 0)
//            throw new Exception('抽奖次数已用完',HTTP_SUCCESS);
        if(!empty($lottery->Config->limit)){
            if ($lottery->get_number >= $lottery->Config->limit) throw new Exception('抽奖次数已经达到上限',HTTP_SUCCESS);
        }
        if ($lottery->status != 1)
            throw new Exception('抽奖不可用',HTTP_SUCCESS);
        if ($lottery->end_time <= now())
            throw new Exception('抽奖已过期',HTTP_SUCCESS);
        return $this;
    }


    public function settlementLottery() : Lottery{
        global $mid;
        $return = $this->return;

        $this->log = LotteryLog::create([
            'user_id' => $this->lottery->user_id,
            'uniqid' => $return['uniqid'],
            'mall_id' => $mid,
            'type' => $return['type'],
            'info' => LotteryLog::getInfo($return['type'],$return['value']),
            'receive' => $return['type'] == 4 ? 2 : 1,
            'style' => $this->lottery->Config->style,
            'number' => $return['number'] ?? 0
        ]);
        if (!empty($this->log) && !empty($this->record))
            $this->record->save(['order_id' => $this->log->id]);
        if (empty($this->price)) {
            LotteryPrize::create([
                'uniqid' => $return['uniqid'],
                'limit' => $return['limit'] ?? 0,
                'count' => 1,
                'number' => $return['number'] ?? 0,
                'integral' => $return['type'] == 2 ? $return['value'] : 0,
                'amount' => $return['type'] == 3 ? $return['value'] : 0,
                'commodity' => $return['type'] == 4 ? json_encode($return['value']) : '{}',
                'value' => json_encode($return),
                'other' => $this->lottery->config->config
            ]);
        }else {
            $this->price->inc('count')->inc('number', $return['number'] ?? 1)->update();
        }

        Lottery::setRecord($this->lottery->user_id,$return,$return['type'],$this->log->id);
        return $this;
    }


    public function getReturn() : array{
        return $this->return;
    }


    public function setReturn(bool $is_bool = false) : Lottery{
        $this->return = Cache::get('lottery'.$this->lottery->user_id);
        $this->setPrize($this->return);
        return $this;
    }

    public function lotteryIntegralDec() : Lottery{
        global $mid;
        if ($this->lottery->total_number > 0)return $this;
        $integral = UserCash::where('user_id',$this->lottery->user_id)->value('integral');
        $lottery_integral = (int)$this->lottery->Config->integral;
        if (empty($this->lottery->Config->integral))return $this;
        if ($this->lottery->Config->integral > $integral)
            throw new Exception('积分不足',HTTP_SUCCESS);

        Db::name('user_cash')
            ->where('user_id',$this->lottery->user_id)
            ->dec('integral',(int)$lottery_integral)
            ->update(['update_time' => now()]);

        $this->record = IntegralRecord::create([
            'user_id' => $this->lottery->user_id,
            'mall_id' => $mid,
            'type' => 9,
            'status' => 1,
            'integral' => $lottery_integral
        ]);
        return $this;
    }


    public function getLotteryReturn(bool $is_bool = false) : Lottery{
        $goods = json_decode($this->lottery->Config->config,true);
        //中奖数字
        $zhongjiang_num = mt_rand(1, 1000)/10; //例：55
//        var_dump($zhongjiang_num);
        //读取商品概率
        foreach($goods as $v)$gailv[] = $v['probability'];
        //计算概率总数：此处原则上总数为100，但是不排除有没有谢谢参与这种商品的情况，所以兼容各种概率设定
        $num_count = array_sum($gailv)*10;
//        var_dump($num_count);
        //生成1到100个数字并组成数组
        for($i=0.1;$i<=100;$i = $i + 0.1)$a[] = round($i, 1);
//        var_dump($a);die();
        //从数组中选出指定个数的随机数并返回键
        $b = array_rand($a,$num_count);
//        var_dump($b);die();
        //由于array_rand读取出的数组中的键，所以多一步将键转化为值的过程
        foreach($b as $v)$c[] = $a[$v];
        //打乱数组排序
        shuffle($c);
        foreach($goods as $k => $v){
            //如果概率不是0
            if($v['probability'] > 0){
                $num_sub = [];
                if($v['probability'] > 0.1){
                    $num_sub_key = array_rand($c,$v['probability'] * 10);
                    foreach($num_sub_key as $vv){
                        $num_sub[] = $c[$vv];
                        unset($c[$vv]);
                    }
                }else{
                    $num_sub_key = array_rand($c);
                    $num_sub[] = $c[$num_sub_key];
                    unset($c[$num_sub_key]);
                }
                $c = array_values($c);
                $goods[$k]['gailv_num'] = $num_sub;
            }else{
                //永远中不到的商品的值设为999，永远匹配不到
                $goods[$k]['gailv_num'][] = 999;
            }
        }
        //检测商品是否中奖了
        foreach($goods as $v) {
            if(in_array($zhongjiang_num, $v['gailv_num'])) {
                $return =  $v;//返回中奖的商品ID
            }
        }
        //此处可加入商品库存检测，代码略
        //一个都没中，当有谢谢参与的商品时，走不到这里，只有概率相加小于100时，可能走到这里
        $this->setPrize($return);
        unset($return['gailv_num']);
        $this->return = $return;
        if ($is_bool)Cache::set('lottery'.$this->lottery->user_id,$this->return,3600);
        return $this;
    }

    public function setPrize(array $return){
        $find = LotteryPrize::where('uniqid' ,$return['uniqid'])->find();
        if (!empty($find) && !empty($return['limit'])){
            $field = $return['type'] == 4 ? 'number' : 'count';
            if ($find[$field] >= $return['limit'])unset($return);
        }
        //超过限制则改为谢谢惠顾
        $this->return = $return ?? ['uniqid' => '000000','probability' => 0,'value' => 0,'type' => 1,'number' => 0,'limit' => 0,'gailv_num' => []];
        $this->price = $find;
    }


    public static function setRecord(int $user_id, array $value, int $type, int $logId) : void{

        self::$user = $user_id;
        if ($type == 1)
            return;
        else if ($type == 2)
            self::integral($value['value']);
        else if ($type == 3)
            self::amount($value['value'] * 100);
        else if ($type == 4)
            self::commodity($value,$logId);
        else if ($type == 5)
            self::coupon($value);
        else return;
    }


    protected static function integral(int $value) : void{
        global $mid;
        IntegralRecord::create([
            'mall_id' => $mid,
            'integral' => $value,
            'type' => 8,
            'status' => 1,
            'number' => 0,
            'commodity_id' => 0,
            'sku_id' => 0,
            'order_id' => 0,
            'user_id' => self::$user,
            'create_time' => date('Y-m-d H:i:s'),
            'update_time' => date('Y-m-d H:i:s')
        ]);
        UserCash::where('user_id',self::$user)
            ->inc('integral',$value)
            ->inc('integral_total',$value)
            ->update(['update_time' => date('Y-m-d H:i:s')]);
    }


    protected static function amount(int $value) : void{
        global $mid,$baseIn;
        $money=floor($value/100);
        $total = UserCash::where('user_id',self::$user)->value('total');
        RechargeRecord::create([
            'mall_id' => $mid,
            'user_id' => self::$user,
            'base_in' => $baseIn,
            'source_type' => 9,
            'source' => '抽奖获得',
            'is_online' => 0,
            'type' => 0,
            'card' => '{}',
            'money' => $money,
            'service_charge' => 0,
            'remark' => '抽奖获得'.$money,
            'trade' => '',
            'pay_no' => '',
            'status' => 1,
            'create_time' => date('Y-m-d H:i:s'),
            'update_time' => date('Y-m-d H:i:s'),
            'new_cash' => $total + $money,
            'old_cash' => $total
        ]);
        UserCash::where('user_id',self::$user)
            ->inc('total',$money)
            ->update(['update_time' => date('Y-m-d H:i:s')]);
    }


    protected static function commodity(array $value, int $logId) : void{
        LotteryLogistics::create([
            'user_id' => self::$user,
            'order_no' => date('YmdHis').rand(100000,999999),
            'lottery_log_id' => $logId,
            'goods_name' => $value['name'],
            'type' => 1,
            'status' => 1,
            'create_time' => date('Y-m-d H:i:s')
        ]);
    }


    protected static function coupon(array $value) : void{
        global $mid;
        $coupon = \think\facade\Db::name('coupon')->find(['id' => $value['value']['coupon_id']]);
        UserCoupon::create([
            'mall_id' => $mid,
            'user_id' => self::$user,
            'coupon_id' => $coupon['id'],
            'merchant_id' => $coupon['merchant_id'],
            'type' => 2,
            'status' => 0
        ]);
    }


    public static function setUserLottery($user, $money) : void{
        $config = Configuration::where('mall_id',$user['mall_id'])
            ->where('type','lottery')
            ->value('configuration');
        if (empty($config))return;
        $config = json_decode($config);
        if (empty($config))return;
        $where[] = ['user_id','=',$user['id']];
        if ($config->lottery_type == 2) {
            if ($money < $config->lottery_money) return;
            if ($config->superposition == 1)
                $number = floor($money / $config->lottery_money);
        }else{
            $where[] = ['create_time','>',date('Y-m-d')];
        }
        $lottery_config = LotteryConfig::where('style',$config->lottery_style)
            ->where('mall_id', $user['mall_id'])
            ->where('status',1)
            ->where('start_time', '<', now())
            ->where('end_time', '>', now())
            ->find();
        if (empty($lottery_config)) return;
        $where[] = ['lottery_id','=',$lottery_config->id];
        $count = \think\facade\Db::name('user_lottery_record')
            ->where($where)
            ->sum('number');
        if ($lottery_config->limit < $count) return ;
        UserLottery::saveLottery($lottery_config,$user,$number ??  (int)$config->lottery_number);
    }
}